import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:froom_generator/value_object/entity.dart';
import 'package:froom_generator/value_object/field.dart';

/// 实体增强代码生成器
/// 基于froom_generator的Entity对象生成copyWith、equals、hashCode等增强方法
class EntityWriter {
  final Entity entity;

  EntityWriter(this.entity);

  /// 生成part文件格式的增强代码
  String generatePartFileCode() {
    final buffer = StringBuffer();
    final className = entity.classElement.name!;

    // 生成Extension用于实例方法
    buffer.writeln('extension ${className}Generated on $className {');

    // 生成copyWith方法
    buffer.writeln(_generateCopyWithMethod());
    buffer.writeln();

    // 生成equals操作符 - 在extension中需要特殊处理
    buffer.writeln(_generateExtensionEqualsOperator());
    buffer.writeln();

    // 生成hashCode - 在extension中需要特殊处理
    buffer.writeln(_generateExtensionHashCode());
    buffer.writeln();

    // 生成toString方法
    buffer.writeln(_generateToString());

    buffer.writeln(_generateStaticMethods());
    buffer.writeln('}');

    return buffer.toString();
  }

  /// 生成copyWith方法
  String _generateCopyWithMethod() {
    final buffer = StringBuffer();
    final className = entity.classElement.name!;

    buffer.writeln('  ${className} copyWith({');

    // 生成参数列表
    for (final field in entity.fields) {
      final fieldName = field.fieldElement.name!;
      final fieldType = _getFieldTypeStringNotNull(field);
      buffer.writeln('    ${fieldType}? ${fieldName},');
    }

    buffer.writeln('  }) {');
    buffer.writeln('    return ${className}(');

    // 生成返回语句
    for (final field in entity.fields) {
      final fieldName = field.fieldElement.name!;
      buffer.writeln('      ${fieldName}: ${fieldName} ?? this.${fieldName},');
    }

    buffer.writeln('    );');
    buffer.writeln('  }');

    return buffer.toString();
  }

  /// 生成extension中的equals操作符（不能直接override）
  String _generateExtensionEqualsOperator() {
    final buffer = StringBuffer();
    final className = entity.classElement.name!;

    buffer.writeln('  bool equals(Object other) =>');
    buffer.writeln('      identical(this, other) ||');
    buffer.writeln('      other is ${className} &&');
    buffer.writeln('          runtimeType == other.runtimeType &&');

    // 排除DateTime字段，只比较主要字段
    final compareFields =
        entity.fields.where((field) => !_isDateTimeField(field)).toList();

    for (int i = 0; i < compareFields.length; i++) {
      final field = compareFields[i];
      final fieldName = field.fieldElement.name!;
      final isLast = i == compareFields.length - 1;
      final suffix = isLast ? ';' : ' &&';
      buffer.writeln('          ${fieldName} == other.${fieldName}${suffix}');
    }

    return buffer.toString();
  }

  /// 生成extension中的hashCode（不能直接override）
  String _generateExtensionHashCode() {
    final buffer = StringBuffer();

    buffer.writeln('  int get hashCodeValue =>');

    // 排除DateTime字段
    final hashFields =
        entity.fields.where((field) => !_isDateTimeField(field)).toList();

    for (int i = 0; i < hashFields.length; i++) {
      final field = hashFields[i];
      final fieldName = field.fieldElement.name!;
      final isLast = i == hashFields.length - 1;
      final operator = isLast ? ';' : ' ^';
      buffer.writeln('      ${fieldName}.hashCode${operator}');
    }

    return buffer.toString();
  }

  /// 生成toString方法
  String _generateToString() {
    final buffer = StringBuffer();
    final className = entity.classElement.name!;

    buffer.writeln('  String toStringValue() {');
    buffer.write('    return \'${className}{');

    final fieldStrings = entity.fields.map((field) {
      final fieldName = field.fieldElement.name!;
      return '${fieldName}: \$${fieldName}';
    }).toList();

    buffer.write(fieldStrings.join(', '));
    buffer.writeln('}\';');
    buffer.writeln('  }');

    return buffer.toString();
  }

  /// 生成静态辅助方法
  String _generateStaticMethods() {
    final buffer = StringBuffer();

    // getTableName方法
    buffer.writeln('  static String getTableName() => \'${entity.name}\';');
    buffer.writeln();

    // getPrimaryKey方法
    buffer.writeln(_generateGetPrimaryKey());
    buffer.writeln();

    // getFieldCol方法
    buffer.writeln(_generateGetFieldCol());
    buffer.writeln();

    // toEntity方法
    buffer.writeln(_generateToEntity());
    buffer.writeln();

    // toMap方法
    buffer.writeln(_generateToMap());

    return buffer.toString();
  }

  /// 生成getPrimaryKey方法
  String _generateGetPrimaryKey() {
    final primaryKeyFields = entity.primaryKey.fields
        .map((field) => '\'${field.columnName}\'')
        .toList();
    return '  static List<String> getPrimaryKey() => [${primaryKeyFields.join(', ')}];';
  }

  /// 生成getFieldCol方法
  String _generateGetFieldCol() {
    final buffer = StringBuffer();
    buffer.writeln('  static Map<String, String> getFieldCol() => {');

    for (final field in entity.fields) {
      final fieldName = field.fieldElement.name!;
      final columnName = field.columnName;
      buffer.writeln('        \'${fieldName}\': \'${columnName}\',');
    }

    buffer.writeln('      };');
    return buffer.toString();
  }

  /// 生成toEntity方法
  String _generateToEntity() {
    final buffer = StringBuffer();
    final className = entity.classElement.name!;

    buffer.writeln(
        '  static ${className} toEntity(Map<String, Object?> map) => ${className}(');

    for (final field in entity.fields) {
      final fieldName = field.fieldElement.name!;
      final columnName = field.columnName;
      final conversion =
          _generateFieldConversion(field, 'map[\'${columnName}\']');
      buffer.writeln('        ${fieldName}: ${conversion},');
    }

    buffer.writeln('      );');
    return buffer.toString();
  }

  /// 生成toMap方法
  String _generateToMap() {
    final buffer = StringBuffer();
    final className = entity.classElement.name!;
    final paramName = entity.classElement.name!.toLowerCase();

    buffer.writeln(
        '  static Map<String, Object?> toMap(${className} ${paramName}) => {');

    for (final field in entity.fields) {
      final fieldName = field.fieldElement.name!;
      final columnName = field.columnName;
      final serialization =
          _generateFieldSerialization(field, '${paramName}.${fieldName}');
      buffer.writeln('        \'${columnName}\': ${serialization},');
    }

    buffer.writeln('      };');
    return buffer.toString();
  }

  /// 生成字段类型字符串
  String _getFieldTypeString(Field field) {
    final type = field.fieldElement.type;
    return type.getDisplayString();
  }

  /// 生成字段类型字符串
  String _getFieldTypeStringNotNull(Field field) {
    final type = _getFieldTypeString(field);
    if (type.endsWith("?")) {
      return type.substring(0, type.length - 1);
    }
    return type;
  }

  /// 判断是否为DateTime字段
  bool _isDateTimeField(Field field) {
    final type = field.fieldElement.type;
    return type.element?.name == 'DateTime';
  }

  /// 生成字段转换代码（从Map到实体）
  String _generateFieldConversion(Field field, String mapValue) {
    final type = field.fieldElement.type;
    final isNullable = type.nullabilitySuffix == NullabilitySuffix.question;

    // 检查是否有TypeConverter
    if (field.typeConverter != null) {
      final converterName = field.typeConverter!.name;
      final sqlType = field.typeConverter!.databaseType.getDisplayString();
      final getConverter = _genTypeConverter(converterName);
      if (isNullable) {
        return '${mapValue} != null ?  ${getConverter}.decode(${mapValue} as ${sqlType} ) : null';
      } else {
        return ' ${getConverter}.decode(${mapValue}  as ${sqlType} )';
      }
    }

    if (type.element?.name == 'DateTime') {
      if (isNullable) {
        return '${mapValue} != null ? DateTime.parse(${mapValue} as String) : null';
      } else {
        return 'DateTime.parse(${mapValue} as String)';
      }
    } else if (type.element?.name == 'bool') {
      if (isNullable) {
        return '${mapValue} != null ? (${mapValue} as int) == 1 : null';
      } else {
        return '(${mapValue} as int) == 1';
      }
    } else if (type.element?.name == 'int') {
      return '${mapValue} as int${isNullable ? '?' : ''}';
    } else if (type.element?.name == 'double') {
      return '${mapValue} as double${isNullable ? '?' : ''}';
    } else if (type.element?.name == 'String') {
      return '${mapValue} as String${isNullable ? '?' : ''}';
    } else {
      // 其他类型，直接转换
      return '${mapValue} as ${_getFieldTypeString(field)}';
    }
  }

  /// 生成字段序列化代码（从实体到Map）
  String _generateFieldSerialization(Field field, String fieldValue) {
    final type = field.fieldElement.type;
    final isNullable = type.nullabilitySuffix == NullabilitySuffix.question;

    // 检查是否有TypeConverter
    if (field.typeConverter != null) {
      final converterName = field.typeConverter!.name;
      final getConverter = _genTypeConverter(converterName);
      if (isNullable) {
        return '${fieldValue} != null ? ${getConverter}.encode(${fieldValue}) : null';
      } else {
        return ' ${getConverter}.encode(${fieldValue})';
      }
    }

    if (type.element?.name == 'DateTime') {
      if (isNullable) {
        return '${fieldValue}?.toIso8601String()';
      } else {
        return '${fieldValue}.toIso8601String()';
      }
    } else if (type.element?.name == 'bool') {
      if (isNullable) {
        return '${fieldValue} != null ? (${fieldValue}! ? 1 : 0) : null';
      } else {
        return '${fieldValue} ? 1 : 0';
      }
    } else {
      // 其他类型直接返回
      return fieldValue;
    }
  }

  String _genTypeConverter(String name) {
    return 'Get.find<${name}>()';
  }
}
